//
//  BSServiceManager.m
//  HappyRoom
//
//  Created by Captain Black on 2016/11/29.
//  Copyright © 2016年 Captain Black. All rights reserved.
//

#import "BrickSetServiceManager.h"
#import <objc/runtime.h>
#import "BrickSet.h"


NSString * const BSServiceRegisteredNotification = @"BSServiceRegisteredNotification";
NSString * const BSServiceUnregisteredNotification = @"BSServiceUnregisteredNotification";
NSString * const BSServiceKey = @"BSServiceKey";
NSString * const BSServiceClassKey = @"BSServiceClassKey";

@interface BrickSetServiceManager ()
@property (nonatomic, strong) NSMutableDictionary *serviceInfo;
@property (nonatomic, strong) NSMutableSet *serviceInitMarks;
@property (nonatomic, strong) NSMutableDictionary *singletonServices;
@end

@implementation BrickSetServiceManager

#pragma mark - singleton
+ (instancetype)sharedInstance {
    static BrickSetServiceManager *g_srvMgr = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        g_srvMgr = [[BrickSetServiceManager alloc] init];
    });
    return g_srvMgr;
}

#pragma mark -
- (void)registerClass:(Class)class forService:(Protocol *)serviceProtocol {
    static NSRecursiveLock* recursiveLock;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        recursiveLock = [[NSRecursiveLock alloc] init];
    });
    [recursiveLock lock];
    {
        if (!protocol_conformsToProtocol(serviceProtocol, @protocol(BSService))) {
            [[NSException exceptionWithName:@"BrickSetException"
                                     reason:@"serviceProtocol must conforms to BSService"
                                   userInfo:nil]
             raise];
            [recursiveLock unlock];
            return;
        }
        if (![class conformsToProtocol:serviceProtocol]) {
            [[NSException exceptionWithName:@"BrickSetException"
                                     reason:[NSString stringWithFormat:@"class must conforms to %@", NSStringFromProtocol(serviceProtocol)]
                                   userInfo:nil]
             raise];
            [recursiveLock unlock];
            return;
        }
        self.serviceInfo[NSStringFromProtocol(serviceProtocol)] = NSStringFromClass(class);
        
        [[NSNotificationCenter defaultCenter] postNotificationName:BSServiceRegisteredNotification
                                                            object:nil
                                                          userInfo:@{BSServiceKey:serviceProtocol,
                                                                     BSServiceClassKey:class
                                                                   }];
    }
    [recursiveLock unlock];
}

- (void)unregisterService:(Protocol *)serviceProtocol {
    static NSRecursiveLock* recursiveLock;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        recursiveLock = [[NSRecursiveLock alloc] init];
    });
    [recursiveLock lock];
    {
        NSString *serviceKey = NSStringFromProtocol(serviceProtocol);
        NSString *className = self.serviceInfo[serviceKey];
        
        Class class = NSClassFromString(className);
        if (class) {
            // 移出服务信息映射表
            [self.serviceInfo removeObjectForKey:serviceKey];
            [self.serviceInitMarks removeObject:serviceKey];
            // 服务信息映射表里已经没有该类映射，清理相关对象
            if (![self.serviceInfo.allValues containsObject:className]) {
                [self.singletonServices removeObjectForKey:className];
            }
            
            [[NSNotificationCenter defaultCenter] postNotificationName:BSServiceUnregisteredNotification
                                                                object:nil
                                                              userInfo:@{BSServiceKey:serviceProtocol,
                                                                         BSServiceClassKey:class
                                                                       }];
        }
    }
    [recursiveLock unlock];
}

- (id<BSService>)instanceForService:(Protocol *)serviceProtocol {
    static NSRecursiveLock* recursiveLock;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        recursiveLock = [[NSRecursiveLock alloc] init];
    });
    [recursiveLock lock];
    {
        NSString *serviceKey = NSStringFromProtocol(serviceProtocol);
        NSString *className = self.serviceInfo[serviceKey];
        Class class = NSClassFromString(className);
        if (!class) {
            [recursiveLock unlock];
            return nil;
        }
        
        SEL initSel = NSSelectorFromString([NSString stringWithFormat:@"init%@", serviceKey]);
        BOOL hasInitMark = [self.serviceInitMarks containsObject:serviceKey];
        
        id<BSService> ret = self.singletonServices[className];
        if (ret) {
            [recursiveLock unlock];
            return ret;
        }
        ret = [[class alloc] init];
        if (ret) {
            // 创建服务，以类名保存类服务
            self.singletonServices[className] = ret;
            if (!hasInitMark &&
                [ret respondsToSelector:initSel]) {
                [ret performSelector:initSel];
                [self.serviceInitMarks addObject:serviceKey];
            }
            [recursiveLock unlock];
            return ret;
        }
    }
    [recursiveLock unlock];
    return nil;
}

#pragma mark - getter & setter
- (NSMutableDictionary *)serviceInfo {
    if (!_serviceInfo) {
        _serviceInfo = [NSMutableDictionary dictionary];
    }
    return _serviceInfo;
}

- (NSMutableSet *)serviceInitMarks {
    if (!_serviceInitMarks) {
        _serviceInitMarks = [NSMutableSet set];
    }
    return _serviceInitMarks;
}

- (NSMutableDictionary *)singletonServices {
    if (!_singletonServices) {
        _singletonServices = [NSMutableDictionary dictionary];
    }
    return _singletonServices;
}

@end
